package com.joven.product.service.infrastructure.converter;

import com.joven.product.service.business.domain.model.entity.id.*;
import com.joven.product.service.business.domain.model.entity.Product;
import com.joven.product.service.business.domain.model.entity.ProductAttribute;
import com.joven.product.service.business.domain.model.entity.ProductDetail;
import com.joven.product.service.business.domain.model.value.Attribute;
import com.joven.product.service.client.dto.*;
import com.joven.product.service.infrastructure.persistence.db.entity.ProductAttributeDO;
import com.joven.product.service.infrastructure.persistence.db.entity.ProductDO;
import com.joven.product.service.infrastructure.persistence.db.entity.ProductDetailDO;
import com.joven.product.service.infrastructure.persistence.db.query.ProductPageQuery;
import org.apache.commons.collections4.CollectionUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.factory.Mappers;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 转换器
 *
 * @author Joven
 * @date 2022-01-06 18:21:27
 */
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface ProductConverter extends BaseConverter<ProductId, Product, ProductDO> {
    ProductConverter INSTANCE = Mappers.getMapper(ProductConverter.class);

    default ProductId toProductId(Long id) {
        return ProductId.builder().status(EntityStatus.UNCHANGED).value(id).build();
    }

    ProductDetailDTO convert(ProductDO productDO);

    void update(ProductCreateDTO dto, @MappingTarget Product.ProductBuilder<?, ?> builder);

    void update(Product product, @MappingTarget Product.ProductBuilder<?, ?> builder);

    @Mapping(source = "id", target = "id", ignore = true)
    @Mapping(source = "detail", target = "detail", ignore = true)
    @Mapping(source = "attributes", target = "attributes", ignore = true)
    void update(ProductEditDTO editDTO, @MappingTarget Product.ProductBuilder<?, ?> builder);

    ProductPageQuery convert(ProductPageQueryDTO dto);

    ProductDTO toProductDTO(ProductDO productDO);

    @Mapper
    interface ProductAttributeAssembler extends BaseConverter<ProductAttributeId, ProductAttribute, ProductAttributeDO> {
        ProductAttributeAssembler INSTANCE = Mappers.getMapper(ProductAttributeAssembler.class);

        default ProductId toProductId(Long id) {
            return ProductId.builder().status(EntityStatus.UNCHANGED).value(id).build();
        }

        default ProductAttributeId convert(Long id) {
            return ProductAttributeId.builder().status(EntityStatus.UNCHANGED).value(id).build();
        }

        @Override
        default ProductAttribute toDomainObj(ProductAttributeDO attributeDO) {
            Attribute attr = convert(attributeDO);
            ProductAttribute.ProductAttributeBuilder<?, ?> builder = ProductAttribute.builder();
            update(attributeDO, builder);
            return builder.attribute(attr).build();
        }

        void update(ProductAttributeDO attributeDO, @MappingTarget ProductAttribute.ProductAttributeBuilder<?, ?> builder);

        void update(Attribute attribute, @MappingTarget ProductAttributeDO attributeDO);

        @Override
        default ProductAttributeDO toDataObj(ProductAttribute domainObj) {
            ProductAttributeDO attributeDO = convert(domainObj);
            update(domainObj.getAttribute(), attributeDO);
            return attributeDO;
        }

        @Override
        default List<ProductAttributeDO> toDataObjs(List<ProductAttribute> attributes) {
            if (CollectionUtils.isEmpty(attributes)) {
                return Collections.emptyList();
            }
            return attributes.stream().map(this::toDataObj).collect(Collectors.toList());
        }

        @Mapping(source = "id", target = "preId", qualifiedByName = "getEntityPreId")
        ProductAttributeDO convert(ProductAttribute domainObj);

        default Long convert(ProductId productId) {
            return productId.getValue();
        }

        Attribute convert(ProductAttributeDO attributeDO);

        Attribute convert(ProductCreateDTO.ProductAttribute attribute);

        Attribute convert(ProductEditDTO.ProductAttribute attribute);

        List<ProductDetailDTO.ProductAttribute> toProductAttributes(List<ProductAttributeDO> attributes);
    }

    @Mapper
    interface ProductDetailAssembler extends BaseConverter<ProductDetailId, ProductDetail, ProductDetailDO> {
        ProductDetailAssembler INSTANCE = Mappers.getMapper(ProductDetailAssembler.class);

        default ProductId toProductId(Long id) {
            return ProductId.builder().status(EntityStatus.UNCHANGED).value(id).build();
        }

        default ProductDetailId toProductDetailId(Long id) {
            return ProductDetailId.builder().status(EntityStatus.UNCHANGED).value(id).build();
        }

        void update(ProductEditDTO.ProductDetail detail, @MappingTarget ProductDetail.ProductDetailBuilder<?, ?> target);

        void update(ProductDetail detail, @MappingTarget ProductDetail.ProductDetailBuilder<?, ?> target);

        default Long convert(ProductId productId) {
            return productId.getValue();
        }

        ProductDetailDTO.ProductDetail convert(ProductDetailDO detailDO);
    }
}
